#ifndef TREE_H
#define TREE_H

#include <iostream>
#include "CircleTree.h"
#include "reshoughtools.h"
#include "branch.h"

using namespace std ;

class Tree
{

private:
    int idTree ;

public:
    unsigned int nbNode;        // Nombre de noeud contenu dans un arbre (nombre de cercles)
    nodePtr root ;
    static int next_idTree ;
    float zmin, zmax ;
    int size ;
    int score_max ;
    vcg::Point3f bot;           /*!< Coin bas-gauche de la bounding box des cercles formant l'arbre */
    vcg::Point3f top;           /*!< Coin haut-droit de la bounding box des cercles formant l'arbre */
    MeshModel*   treeMesh;      /*!< Pointeur vers le mesh engendre par l'arbre */

    // ************************** Constructors - destructors **************************
    Tree () ;
    Tree (CircleTree *c) ;
    ~Tree() ;

    inline unsigned int getIdTree () {return idTree ;}

    // ************************** Operations on trees **************************
private:
    void changeIdTree_aux (nodePtr tn, int id) ;
public:
    void changeIdTree (int id) ;

private:
    nodePtr getCircleNode_aux (nodePtr tn, CircleTree c) ;
public:
    nodePtr getCircleNode (CircleTree c) ;

    // ************************** Operations on trees **************************
private:
    void traverseTree_aux (nodePtr p) ;
public:
    void traverseTree () ;
private:
    void drawTree_aux(CMeshO &_m, nodePtr p, int pi, bool draw_circles = false) ;
public :
    void drawTree(MeshDocument &m, bool draw_circles = false) ;

public :
    // ************************** Ajout d'un noeud a un maillage  **************************
    int drawNode (nodePtr &node, int fatherCenterVertexIndex, CMeshO &m, bool draw_circles = false); // Renvoie l'index du vertex centre du cercle de node dans le maillage

    // ************************** Comparaison d'arbres **************************
    /*!
     * \brief distance
     *
     * Calcule une metrique de similarite entre deux arbres donnes
     *
     * \param t : L'arbre avec lequel l'objet courant est compare
     * \return la distance entre les deux arbres
     */
    float   distance ( Tree& t );

    // ************************** Operations sur la bounding box **************************
    /*!
     * \brief updateBBox
     *
     * Met a jour la bounding box de l'arbre en fonction du centre du cercle apsse en parametre
     *
     * \param c : Cercle qui peut modifier la bounding box de l'arbre
     */
    void updateBBox ( CircleTree* c );

    /*!
     * \brief updateBBox
     *
     * Met a jour la bounding box de l'arbre en fonction de celle de l'arbre t avec lequel il va fusionner
     *
     * \param t : Arbre qui va fusionner avec l'objet appellant la methode
     */
    void updateBBox ( Tree* t );

    // ************************** Autres **************************
    /*!
     * \brief getSoilHeight
     *
     * Calcule la hauteur de la base de l'arbre dans le repere cartesien
     *
     * \param mntGrid : Grille dans laquelle a ete plonge le MNT correspondant a l'arbre
     * \return Renvoie la hauteur dans le repere global de la base de l'arbre
     */
    float getSoilHeight (vcg::GridStaticPtr<vcg::Point3f, float> &mntGrid );

    // Renvoi les cercles immediatement au dessus et au dessous de la hauteur demandee
    bool getCirclesAroundHeight ( float height, vector< CircleTree* >& outputBot, vector< CircleTree* >& outputTop );

    // Partie recursive de la methode precedente (on aurait pu n'en faire qu'une)
    bool getCirclesAroundHeightAux ( float height, vector< CircleTree* >& outputBot, vector< CircleTree* >& outputTop, nodePtr node );

    void decomposeIntoBranches (vector<Branch *> &output , nodePtr startingNode, nodePtr father);

};




#endif // TREE_H
